package db

import (
	"errors"
	"log"
	"strconv"
	"strings"
	"time"
	"xiaoniu-job/internal"
	"xiaoniu-job/pkg"
)

const (
	timeFormat = "2006-01-02 15:04:05"
)

/**
任务的增删改查
*/

func GetTaskById(id uint64) (*pkg.Task, error) {
	var task pkg.Task
	err := GetGlobalDb().Limit(1).Find(&task, id).Error
	if err != nil {
		return nil, err
	}
	return &task, nil
}

// AddTask 新增任务
func AddTask(task *pkg.Task) (int64, error) {
	// 判断任务名称和所属执行器是否重复
	if task.TaskName == "" {
		return 0, errors.New("任务名称不能为空")
	}
	if task.TaskLabel == "" {
		return 0, errors.New("任务唯一标识不能为空")
	}
	if task.ExecutorId == 0 {
		return 0, errors.New("所属执行器不能为空")
	}
	if task.Strategy == "" {
		return 0, errors.New("任务执行策略不能为空")
	}
	if task.Cron == "" {
		return 0, errors.New("任务定时策略不能为空")
	}
	var oldTask pkg.Task
	first := GetGlobalDb().Where("task_name = ?", task.TaskName).Where("executor_id = ?",
		task.ExecutorId).Limit(1).Find(&oldTask).RowsAffected
	if first != 0 {
		return 0, errors.New("该任务已存在")
	}
	create := GetGlobalDb().Create(task)
	return create.RowsAffected, create.Error
}

// UpdateTask 更新任务
func UpdateTask(task *pkg.Task) (int64, error) {
	if task.Id == 0 {
		return 0, errors.New("任务Id不能为空")
	}
	if task.TaskName == "" {
		return 0, errors.New("任务名称不能为空")
	}
	if task.TaskLabel == "" {
		return 0, errors.New("任务唯一标识不能为空")
	}
	if task.ExecutorId == 0 {
		return 0, errors.New("所属执行器不能为空")
	}
	if task.Strategy == "" {
		return 0, errors.New("任务执行策略不能为空")
	}
	if task.Cron == "" {
		return 0, errors.New("任务定时策略不能为空")
	}
	oldTask, _ := GetTaskById(task.Id)
	columns := GetGlobalDb().Save(task)
	// 从开启到关闭，需要关闭对应的cron定时任务
	if columns.RowsAffected > 0 && oldTask != nil && oldTask.Status == 1 && task.Status == 0 {
		internal.UpdateTaskChan <- task
		//go cron.RemoveTaskCron(task)
	}
	return columns.RowsAffected, columns.Error
}

// DeleteTask 删除任务
func DeleteTask(id uint64) (int64, error) {
	tx := GetGlobalDb().Delete(&pkg.Task{Id: id})
	return tx.RowsAffected, tx.Error
}

func GetTaskList(search *pkg.TaskSearch) *pkg.QueryListResponse {
	var data []pkg.Task
	tx := GetGlobalDb().Model(&pkg.Task{})
	if search.TaskName != "" {
		tx.Where("task_name LIKE ?", "%"+search.TaskName+"%")
	}
	if search.ExecutorId != "" {
		intNum, _ := strconv.Atoi(search.ExecutorId)
		int64Num := uint64(intNum)
		tx.Where("executor_id = ?", int64Num)
	}
	// 计算总数
	var total int64
	tx.Count(&total)
	err := tx.Limit(search.PageSize).Offset((search.PageNo - 1) *
		search.PageSize).Find(&data).Error
	if err != nil {
		var res = make([]pkg.Task, 0)
		return pkg.NewQueryListResponse(total, res, err)
	}
	return pkg.NewQueryListResponse(total, data, err)
}

// GetStartingTask 获取状态是开启的定时任务
func GetStartingTask() []pkg.Task {
	var data []pkg.Task
	err := GetGlobalDb().Where("status = 1").Model(&pkg.Task{}).Find(&data).Error
	if err != nil {
		var res = make([]pkg.Task, 0)
		return res
	}
	return data
}

// GetTaskMapForSelect 获取任务下拉列表
func GetTaskMapForSelect() *pkg.QueryListResponse {
	var data []pkg.TaskSelect
	tx := GetGlobalDb().Model(&pkg.Task{})
	// 计算总数
	var total int64
	tx.Count(&total)
	err := tx.Find(&data).Error
	if err != nil {
		var res = make([]pkg.TaskSelect, 0)
		return pkg.NewQueryListResponse(total, &res, err)
	}
	return pkg.NewQueryListResponse(total, &data, err)
}

/**
执行器的增删改查
*/

func GetExecutorById(id uint64) (*pkg.Executor, error) {
	var executor pkg.Executor
	err := GetGlobalDb().Limit(1).Find(&executor, id).Error
	if err != nil {
		return nil, err
	}
	return &executor, nil
}

// AddExecutor 新增执行器
func AddExecutor(executor *pkg.Executor) (int64, error) {
	// 判断执行器名称是否重复
	var oldExecutor pkg.Executor
	first := GetGlobalDb().Where("name = ?", executor.Name).Limit(1).Find(&oldExecutor).RowsAffected
	if first != 0 {
		return 0, errors.New("执行器名称已存在")
	}
	create := GetGlobalDb().Create(executor)
	return create.RowsAffected, create.Error
}

// UpdateExecutor 更新执行器
func UpdateExecutor(executor *pkg.Executor) (int64, error) {
	if executor.Id == 0 {
		return 0, errors.New("执行器Id不存在")
	}
	var oldExecutor pkg.Executor
	first := GetGlobalDb().Where("name = ?", executor.Name).Where("id != ?",
		executor.Id).Limit(1).Find(&oldExecutor).RowsAffected
	if first != 0 {
		return 0, errors.New("执行器名称已存在")
	}
	update := GetGlobalDb().Save(executor)
	return update.RowsAffected, update.Error
}

// DeleteExecutor 删除执行器
func DeleteExecutor(id uint64) (int64, error) {
	d := GetGlobalDb().Delete(&pkg.Executor{Id: id})
	return d.RowsAffected, d.Error
}

func GetExecutorList(search *pkg.ExecutorSearch) *pkg.QueryListResponse {
	var data []pkg.Executor
	tx := GetGlobalDb().Model(&pkg.Executor{})
	if search.ExecutorName != "" {
		tx.Where("name LIKE ?", "%"+search.ExecutorName+"%")
	}
	// 计算总数
	var total int64
	tx.Count(&total)
	err := tx.Limit(search.PageSize).Offset((search.PageNo - 1) *
		search.PageSize).Find(&data).Error
	if err != nil {
		var res = make([]pkg.Executor, 0)
		return pkg.NewQueryListResponse(total, &res, err)
	}
	return pkg.NewQueryListResponse(total, &data, err)
}

// GetExecutorMapForSelect 获取执行器下拉列表
func GetExecutorMapForSelect() *pkg.QueryListResponse {
	var data []pkg.ExecutorSelect
	tx := GetGlobalDb().Model(&pkg.Executor{})
	// 计算总数
	var total int64
	tx.Count(&total)
	err := tx.Find(&data).Error
	if err != nil {
		var res = make([]pkg.ExecutorSelect, 0)
		return pkg.NewQueryListResponse(total, &res, err)
	}
	return pkg.NewQueryListResponse(total, &data, err)
}

// SaveExecutor 接收执行器客户端的注册请求并更新到数据库，如果有的话，更新，没有的话则新增
// 接受执行器客户端的取消注册请求并更新到数据库，如果没找到该执行器，则直接返回，找到执行器的时候就需要将自己的ip剔除
func SaveExecutor(request *pkg.HeartBeatRequest) (bool, error) {
	if request.Ip == "" {
		return false, errors.New("执行器IP不能为空！")
	}
	if request.Port == "" {
		return false, errors.New("执行器端口不能为空！")
	}
	if request.Name == "" {
		return false, errors.New("执行器名称不能为空！")
	}
	if request.Type != 1 && request.Type != 2 {
		return false, errors.New("请求类型错误！")
	}

	if request.Type == 1 {
		var res pkg.Executor
		// 根据名称查看当前执行器是否已经存在
		first := GetGlobalDb().Where("name = ?", request.Name).Limit(1).Find(&res)
		if first.Error != nil {
			return false, errors.New("查询执行器出错")
		}
		executorAddress := "http://" + request.Ip + ":" + request.Port
		if first.RowsAffected > 0 {
			// 存在该执行器
			existExecutorAddresses := res.Addresses
			if strings.Contains(existExecutorAddresses, executorAddress) {
				// 说明已经添加过 do nothing
			} else {
				if existExecutorAddresses != "" {
					res.Addresses = existExecutorAddresses + "," + executorAddress
				} else {
					res.Addresses = executorAddress
				}

				save := GetGlobalDb().Save(res)
				return save.RowsAffected > 0, save.Error
			}
			return true, nil
		} else {
			// 不存在该执行器
			res.Addresses = executorAddress
			res.Name = request.Name
			create := GetGlobalDb().Create(&res)
			return create.RowsAffected > 0, create.Error
		}
	} else {
		var res pkg.Executor
		// 根据名称查看当前执行器是否已经存在
		first := GetGlobalDb().Where("name = ?", request.Name).Limit(1).Find(&res)
		if first.Error != nil {
			return false, errors.New("查询执行器出错")
		}
		executorAddress := "http://" + request.Ip + ":" + request.Port
		if first.RowsAffected > 0 {
			// 存在该执行器
			existExecutorAddresses := res.Addresses
			if strings.Contains(existExecutorAddresses, executorAddress) {
				arr := strings.Split(existExecutorAddresses, ",")
				var newArr []string
				for _, addr := range arr {
					if addr != executorAddress {
						newArr = append(newArr, addr)
					}
				}
				res.Addresses = strings.Join(newArr, ",")
				save := GetGlobalDb().Save(res)
				return save.RowsAffected > 0, save.Error
			}
			return true, nil
		} else {
			// 不存在该执行器 do nothing
			return false, nil
		}
	}

}

// FlushExecutorAddresses 服务端程序启动时将所有的执行器地址全部清空，等待执行器客户端心跳发送过来之后更新执行器地址
func FlushExecutorAddresses() {
	updates := GetGlobalDb().Model(&pkg.Executor{}).Where("1 = 1").Update("addresses", "")
	log.Println("清空执行器地址完毕，更新记录数：", updates.RowsAffected, updates.Error)
}

/**
调度日志增删改查
*/

// AddJobLog 新增调度日志
func AddJobLog(log *pkg.JobLog) (int64, error) {
	create := GetGlobalDb().Create(log)
	return create.RowsAffected, create.Error
}

// UpdateJobLog 更新调度日志
func UpdateJobLog(log *pkg.JobLog) (int64, error) {
	update := GetGlobalDb().Save(log)
	return update.RowsAffected, update.Error
}

// UpdateJobLogResultByTaskId 保存任务执行结果，并将执行状态置为执行成功
func UpdateJobLogResultByTaskId(taskId uint64, endTime time.Time, result string) (int64, error) {
	exec := GetGlobalDb().Exec("UPDATE job_logs SET result = ?, end_time = ? , status = 3 WHERE id = ?", result,
		endTime, taskId)
	return exec.RowsAffected, exec.Error
}

// DeleteJobLog 删除调度日志
func DeleteJobLog(id uint64) (int64, error) {
	tx := GetGlobalDb().Delete(&pkg.JobLog{Id: id})
	return tx.RowsAffected, tx.Error
}

func GetLogList(search *pkg.LogSearch) *pkg.QueryListResponse {
	var data []pkg.JobLogDto
	tx := GetGlobalDb().Model(&pkg.JobLog{})
	if search.TaskId != "" {
		intNum, _ := strconv.Atoi(search.TaskId)
		int64Num := uint64(intNum)
		tx.Where("task_id = ?", int64Num)
	}
	if search.ExecutorName != "" {
		tx.Where("executor_name like ?", "%"+search.ExecutorName+"%")
	}
	if search.JobStartTimeStart != "" {
		now, _ := time.ParseInLocation(`"`+timeFormat+`"`, search.JobStartTimeStart, time.Local)
		tx.Where("start_time >= ?", now)
	}
	if search.JobStartTimeEnd != "" {
		now, _ := time.ParseInLocation(`"`+timeFormat+`"`, search.JobStartTimeEnd, time.Local)
		tx.Where("start_time <= ?", now)
	}

	// 计算总数
	var total int64
	tx.Count(&total)
	err := tx.Limit(search.PageSize).Offset((search.PageNo - 1) *
		search.PageSize).Find(&data).Error
	if err != nil {
		var res = make([]pkg.JobLog, 0)
		return pkg.NewQueryListResponse(total, &res, err)
	}
	return pkg.NewQueryListResponse(total, &data, err)
}

// GetJobLogById 根据唯一Id查询调度日志
func GetJobLogById(id uint64) (*pkg.JobLog, error) {
	var jobLog pkg.JobLog
	err := GetGlobalDb().Limit(1).Find(&jobLog, id).Error
	if err != nil {
		return nil, err
	}
	return &jobLog, nil
}
